<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}HTTP 数据服务器{% endblock %}</title>
    <!-- Google Fonts for Noto Sans SC -->
    <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <!-- Font Awesome for map icons (e.g., marker, circle) -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
    <!-- Flatpickr (日期时间选择器) CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
    <style>
        /* CSS Variables for theming */
        :root {
            --primary-color: #3498db;
            --primary-hover-color: #2980b9;
            --secondary-color: #95a5a6;
            --secondary-hover-color: #7f8c8d;
            --background-color: #f4f7f6;
            --container-bg-color: #ffffff;
            --text-color: #333;
            --heading-color: #2c3e50;
            --border-color: #e0e0e0;
            --card-header-bg: #ecf0f1;
            --card-header-hover-bg: #e0e0e0;
            --summary-bg: #eaf3f8;
            --error-color: #e74c3c;
            --warning-color: #f39c12;
            --success-color: #27ae60;
            --highlight-bg: #ffeaa7; /* 浅黄色高亮背景 */
            --code-bg: #f8f8f8;
            --table-header-bg: #f2f2f2;
            --table-row-hover-bg: #f9f9f9;
            --id-card-bg-yellow: #fffdf7; /* 浅黄色卡片背景 */
            
            /* 新增：ID 分组头部浅蓝色样式 */
            --id-group-header-bg-light: #e7f3fd; /* 浅蓝色 */
            --id-group-header-hover-light: #d0e6fb; /* 鼠标悬停时的浅蓝色 */
            --id-group-header-text-light: var(--heading-color); /* 头部文字颜色 */
            --id-group-border-light: #c0dffb; /* ID分组边框颜色 */
        }

        /* Base Body Styles */
        body {
            font-family: 'Noto Sans SC', sans-serif, Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: var(--background-color);
            color: var(--text-color);
            line-height: 1.6;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            display: flex; /* Flexbox for full page layout */
            flex-direction: column;
            min-height: 100vh; /* Full viewport height */
        }
        
        /* Header/Navigation styles */
        .page-header-nav {
            background-color: var(--container-bg-color);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
            padding: 15px 40px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-shrink: 0; /* Don't shrink header */
        }
        /* 修改 .site-title 样式，使其更适合作为图片容器 */
        .page-header-nav .site-title {
            text-decoration: none; /* 保持链接下划线去除 */
            display: flex; /* 使用 flexbox 布局来垂直居中图片 */
            align-items: center; /* 垂直居中对齐图片 */
        }
        /* 新增：Logo 图片的样式 */
        .header-logo {
            height: 60px; /* **修改：增加 Logo 图片的高度** */
            width: auto; /* 保持图片比例 */
            /* 如果图片旁边有文字，可以添加 margin-right: 10px; */
        }

        .nav-links {
            display: flex;
            gap: 15px;
        }
        .nav-links a {
            text-decoration: none;
            color: var(--primary-color);
            font-weight: 500;
            font-size: 1.1em;
            padding: 8px 15px;
            border-radius: 6px;
            transition: background-color 0.2s ease, color 0.2s ease;
        }
        .nav-links a:hover, .nav-links a.active {
            color: white;
            background-color: var(--primary-color);
        }
        .nav-links a.active {
            box-shadow: 0 2px 5px rgba(52, 152, 219, 0.3);
        }

        /* Main Content Wrapper */
        .content-wrapper {
            flex-grow: 1; /* Allow content to grow and take available space */
            padding: 30px 0; /* Vertical padding for content */
        }
        .container {
            max-width: 1200px;
            margin: 0 auto; /* Center the container */
            background-color: var(--container-bg-color);
            padding: 30px 40px;
            border-radius: 12px;
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
        }
        
        /* Headings */
        h1, h2, h3 {
            color: var(--heading-color);
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 12px;
            margin-top: 30px;
            margin-bottom: 25px;
            font-weight: 500;
        }
        h1 { font-size: 2.4em; font-weight: 700; }
        h2 { font-size: 2.0em; }
        h3 { font-size: 1.6em; }

        /* Card Styles */
        .card {
            background-color: var(--container-bg-color);
            border: 1px solid var(--border-color);
            border-radius: 8px;
            margin-bottom: 15px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
            overflow: hidden;
            transition: box-shadow 0.2s ease;
        }
        .card.id-card-yellow {
            background-color: var(--id-card-bg-yellow);
            border-color: #fce8a6;
        }
        .card:hover {
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
        }
        .card-header {
            background-color: var(--card-header-bg);
            padding: 15px 20px;
            border-bottom: 1px solid var(--border-color);
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-weight: 600;
            font-size: 1.1em;
            color: var(--heading-color);
            user-select: none;
            transition: background-color 0.2s ease;
        }
        .card.id-card-yellow .card-header {
             background-color: #fcf8e3;
             border-bottom-color: #fce8a6;
        }
        .card-header:hover {
            background-color: var(--card-header-hover-bg);
        }
        .card-title-text {
            font-weight: normal;
            color: var(--text-color);
        }
        /* Independent message card toggle icon */
        .card-toggle-icon {
            font-size: 1.2em;
            margin-left: 15px;
            transform: rotate(0deg);
            transition: transform 0.2s ease-in-out;
        }
        .card-toggle-icon.rotated {
            transform: rotate(90deg);
        }
        .card-content {
            padding: 0 20px;
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease-out, padding 0.3s ease-out;
        }
        .card-content.expanded {
            max-height: 1000px; /* Still a limit for small cards, avoid excessive scrolling */
            padding-top: 15px;
            padding-bottom: 15px;
        }
        
        /* Table Styles within Card Content */
        .card-content table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
            font-size: 0.9em;
            table-layout: fixed;
        }
        .card-content thead th {
            background-color: var(--table-header-bg);
            padding: 8px 10px;
            border-bottom: 1px solid var(--border-color);
            text-align: left;
            font-weight: 500;
            color: var(--heading-color);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .card-content tbody td {
            padding: 8px 10px;
            border-bottom: 1px solid var(--border-color);
            vertical-align: top;
            white-space: nowrap; 
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .card-content tbody tr:hover {
            background-color: var(--table-row-hover-bg);
        }
        .card-content tbody tr:last-child td {
            border-bottom: none;
        }
        .card-content th.col-locate-time, .card-content td.col-locate-time { width: 100px; }
        .card-content th.col-coords, .card-content td.col-coords { width: 130px; } 
        .card-content th.col-altitude, .card-content td.col-altitude { width: 80px; }
        .card-content th.col-custom-data, .card-content td.col-custom-data { min-width: 180px; max-width: 300px; }

        /* Code Block for raw JSON */
        .code-block {
            background-color: var(--code-bg);
            border: 1px solid var(--border-color);
            padding: 12px;
            border-radius: 6px;
            white-space: pre-wrap;
            word-break: break-all;
            font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
            font-size: 0.85em;
            margin-top: 10px;
            max-height: 350px;
            overflow: auto;
        }

        /* Buttons */
        .button {
            display: inline-block;
            padding: 10px 20px;
            background-color: var(--primary-color);
            color: white;
            text-decoration: none;
            border-radius: 66px; /* 更圆润的圆角 */
            transition: background-color 0.2s ease, transform 0.1s ease;
            font-size: 0.95em;
            font-weight: 500;
            border: none;
            cursor: pointer;
        }
        .button:hover {
            background-color: var(--primary-hover-color);
            transform: translateY(-1px);
        }
        .button:active {
            transform: translateY(0);
        }
        .button.secondary {
            background-color: var(--secondary-color);
        }
        .button.secondary:hover {
            background-color: var(--secondary-hover-color);
        }
        /* 新增：小尺寸按钮 */
        .button.small {
            padding: 6px 12px;
            font-size: 0.85em;
        }
        /* 按钮组 */
        .button-group {
            display: flex; /* 使用 flexbox 布局按钮 */
            gap: 8px; /* 按钮之间的间距 */
            flex-wrap: wrap; /* 允许按钮在小屏幕上换行 */
            margin-top: 10px; /* 如果需要，为按钮组添加顶部间距 */
        }


        /* Status Texts */
        .error-text { color: var(--error-color); font-weight: bold; }
        .warning-text { color: var(--warning-color); font-weight: bold; }
        .success-text { color: var(--success-color); font-weight: bold; }

        /* Highlight for search results */
        .highlight {
            background-color: var(--highlight-bg);
            padding: 1px 3px;
            border-radius: 3px;
            display: inline; /* Keep as inline for text flow */
            box-decoration-break: clone;
            -webkit-box-decoration-break: clone;
        }
        /* Fix for letter-spacing in card headers with highlight */
        .card-header .highlight {
            letter-spacing: normal;
            word-spacing: normal;
        }

        /* Search Controls */
        .search-controls {
            background-color: #fcfcfc;
            border: 1px solid var(--border-color);
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 30px;
            display: grid;
            grid-template-columns: 2fr 1fr;
            gap: 20px;
            align-items: flex-end;
        }
        .search-controls label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: var(--heading-color);
            font-size: 0.95em;
        }
        .search-controls input[type="text"],
        .search-controls select,
        .search-controls .flatpickr-input { /* Target Flatpickr input directly */
            width: 100%;
            padding: 10px 12px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 1em;
            box-sizing: border-box;
            transition: border-color 0.2s ease, box-shadow 0.2s ease;
            background-color: white;
        }
        .search-controls input[type="text"]:focus,
        .search-controls select:focus,
        .search-controls .flatpickr-input:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
            outline: none;
        }
        .search-controls .input-group {
            display: flex;
            gap: 10px;
        }
        .search-controls .input-group input {
            flex-grow: 1;
        }
        /* Radio button styles */
        .search-controls .radio-group {
            display: flex;
            gap: 20px;
            margin-top: 10px;
            align-items: center;
        }
        .search-controls .radio-group label {
            display: flex;
            align-items: center;
            margin-bottom: 0;
            font-weight: normal;
        }
        .search-controls .radio-group input[type="radio"] {
            margin-right: 5px;
            width: auto;
        }
        /* 新增：让 .full-width 占据所有列 */
        .search-controls .full-width {
            grid-column: 1 / -1; /* 确保时间选择器和按钮组占据所有列宽 */
            width: 100%;
            /* 添加 flexbox 布局以更好地控制内部元素 */
            display: flex;
            flex-direction: column; /* 垂直排列标签、输入框和按钮组 */
            gap: 10px; /* 元素之间的间距 */
        }


        /* Summary Stats */
        .summary-stats {
            background-color: var(--summary-bg);
            border-left: 6px solid var(--primary-color);
            padding: 20px 25px;
            margin-bottom: 30px;
            border-radius: 8px;
            display: flex;
            justify-content: space-around;
            flex-wrap: wrap;
            gap: 20px;
        }
        .summary-item {
            text-align: center;
            flex: 1;
            min-width: 150px;
        }
        .summary-item .label {
            font-size: 0.9em;
            color: #555;
            margin-bottom: 5px;
        }
        .summary-item .value {
            font-size: 2.2em;
            font-weight: 700;
            color: var(--heading-color);
            margin-top: 5px;
        }
        
        /* No Data Message */
        .no-data-message {
            text-align: center;
            padding: 50px;
            font-size: 1.3em;
            color: #7f8c8d;
            background-color: #f0f3f5;
            border-radius: 10px;
            margin-top: 40px;
            border: 1px dashed #c0c7cb;
        }
        .no-data-message.error {
            border: 2px dashed var(--error-color);
            color: var(--error-color);
            background-color: #fdf3f3;
        }

        /* Message Metadata in Card Content */
        .message-meta {
            padding: 10px 0;
            border-bottom: 1px solid var(--border-color);
            font-size: 0.9em;
            color: #555;
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 10px;
            align-items: center;
        }
        .message-meta .item {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .message-meta .item span {
            font-weight: 500;
            color: var(--heading-color);
        }

        /* ID Grouping Styles */
        .id-group {
            margin-bottom: 25px;
            border: 1px solid var(--id-group-border-light);
            border-radius: 10px;
            background-color: var(--container-bg-color);
            box-shadow: 0 4px 10px rgba(0,0,0,0.05);
            overflow: hidden;
        }
        .id-group-header {
            padding: 15px 20px;
            background-color: var(--id-group-header-bg-light);
            color: var(--id-group-header-text-light);
            font-weight: 600;
            font-size: 1.2em;
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;
            user-select: none;
            transition: background-color 0.2s ease;
        }
        .id-group-header:hover {
            background-color: var(--id-group-header-hover-light);
        }
        .id-group-header .id-text {
            font-weight: bold;
            color: var(--id-group-header-text-light);
            margin-right: 10px;
        }
        .id-group-header .id-group-toggle-icon {
            font-size: 1.2em;
            margin-left: 15px;
            color: var(--id-group-header-text-light);
            transform: rotate(0deg); /* Default (expanded) */
            transition: transform 0.2s ease-in-out;
        }
        .id-group-header .id-group-toggle-icon.rotated {
            transform: rotate(-90deg); /* Collapsed */
        }
        .id-group-content {
            padding: 15px 20px;
            max-height: none; /* Expanded by default */
            overflow: visible;
            transition: max-height 0.3s ease-out, padding 0.3s ease-out;
        }
        .id-group-content.collapsed {
            max-height: 0;
            padding-top: 0;
            padding-bottom: 0;
            overflow: hidden;
        }
        
        /* Footer */
        .page-footer {
            margin-top: auto; /* Push footer to bottom */
            padding: 20px;
            text-align: center;
            background-color: var(--card-header-bg);
            border-top: 1px solid var(--border-color);
            color: #555;
            font-size: 0.9em;
            flex-shrink: 0; /* Don't shrink footer */
        }

        /* Map page specific layout */
        body.map-body { /* Add this class to body tag on map page */
            overflow: hidden; /* Prevent body scroll when map fills screen */
        }
        .map-wrapper {
            display: flex;
            flex-grow: 1; /* Map content takes remaining space */
            height: calc(100vh - 60px); /* Adjust based on header height, e.g., 60px */
            /* The .container for map page should be full width/height and no padding */
            max-width: none;
            margin: 0;
            padding: 0;
            box-shadow: none;
            border-radius: 0;
        }
        .map-sidebar {
            flex: 0 0 300px; /* Fixed width for sidebar */
            background-color: var(--container-bg-color);
            padding: 20px;
            border-right: 1px solid var(--border-color);
            overflow-y: auto;
            max-height: 100%;
        }
        .map-view-container {
            flex-grow: 1; /* Map itself takes remaining horizontal space */
            height: 100%; /* Fill parent height */
        }
        .map-view {
            width: 100%;
            height: 100%;
        }

        /* Responsive Adjustments */
        @media (max-width: 992px) {
            .page-header-nav { padding: 10px 20px; }
            .page-header-nav .site-title { /* 响应式调整图片大小 */ }
            .header-logo { height: 50px; } /* **修改：小屏幕下 Logo 稍大** */
            .nav-links { gap: 10px; }
            .nav-links a { padding: 6px 12px; font-size: 1em; }

            .container {
                padding: 25px;
                margin: 0 15px; /* Adjust margin for smaller screens */
            }
            h1 { font-size: 2em; }
            h2 { font-size: 1.6em; }
            .card-header { font-size: 1em; padding: 12px 15px; }
            .card-content thead th, .card-content tbody td { padding: 6px 8px; font-size: 0.85em; }
            .search-controls {
                grid-template-columns: 1fr;
            }
            /* 确保在单列布局下，full-width div 恢复默认的 grid-column */
            .search-controls .full-width {
                grid-column: auto; 
            }
            .summary-stats {
                flex-direction: column;
                align-items: center;
            }
            .summary-item {
                width: 100%;
                margin: 10px 0;
            }
            .id-group-header { font-size: 1em; padding: 12px 15px; }
            
            .map-wrapper {
                flex-direction: column; /* Stack sidebar and map vertically */
                height: auto;
            }
            .map-sidebar {
                flex: none; /* Reset flex for stacking */
                width: 100%; /* Full width for sidebar */
                border-right: none;
                border-bottom: 1px solid var(--border-color);
                max-height: 50vh; /* Limit sidebar height */
            }
            .map-view-container {
                height: 60vh; /* Map takes more height */
            }
        }
        @media (max-width: 576px) {
            .page-header-nav { flex-direction: column; align-items: flex-start; gap: 10px; }
            .page-header-nav .site-title { margin-bottom: 5px; }
            .header-logo { height: 40px; } /* **修改：更小屏幕下 Logo 进一步缩小** */
            .nav-links { flex-wrap: wrap; }
            .container {
                padding: 15px;
                margin: 0 10px;
                border-radius: 8px;
            }
            h1 { font-size: 1.8em; }
            .card-header {
                flex-direction: column;
                align-items: flex-start;
                gap: 5px;
            }
            .card-toggle-icon { margin-left: 0; }
            .card-content { padding: 0 15px; }
            .card-content.expanded { padding-left: 15px; padding-right: 15px; }
            .button { padding: 8px 15px; font-size: 0.9em; }
            
            .card-content table {
                display: block;
                overflow-x: auto;
                -webkit-overflow-scrolling: touch;
            }
            .card-content thead, .card-content tbody {
                display: table;
                width: 100%;
            }
            .card-content tr {
                display: table-row;
            }
            .card-content th, .card-content td {
                display: table-cell;
                min-width: 80px;
            }
            .id-group-header {
                flex-direction: column;
                align-items: flex-start;
                gap: 5px;
            }
        }
    </style>
</head>
<body>
    <header class="page-header-nav">
        <a class="site-title" href="{{ url_for('index') }}">
            <!-- 替换为图片 -->
            <img src="{{ url_for('static', filename='images/logo.png') }}" alt="数据展示系统 Logo" class="header-logo">
            <!-- 如果希望在图片旁边保留文字，可以这样： -->
            <!-- <span style="margin-left: 10px; color: var(--heading-color);">数据展示系统</span> -->
        </a>
        <nav class="nav-links">
            <a class="{% if request.path == url_for('index') %}active{% endif %}" href="{{ url_for('index') }}">首页</a>
            <a class="{% if request.path == url_for('map_page') %}active{% endif %}" href="{{ url_for('map_page') }}">地图</a>
            {# Additional navigation links can be added here using block nav_extra_links #}
            {% block nav_extra_links %}{% endblock %}
        </nav>
    </header>

    <main class="content-wrapper">
        <div class="container">
            <h1>{% block page_title %}{% endblock %}</h1>
            {% block content %}{% endblock %}
        </div>
    </main>

    <footer class="page-footer">
        <p>&copy; 湖南泽天智航电子技术有限公司 All Rights Reserved.</p>
    </footer>

    <!-- Flatpickr (日期时间选择器) JS -->
    <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
    <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/zh.js"></script> <!-- 中文本地化 -->
    <script>
        // Flatpickr 中文配置
        flatpickr.setDefaults({
            locale: "zh"
        });

        // 定义表格的列和对应的键，仅包含核心的定位信息 (在 base.html 中定义，所有页面共享)
        const TABLE_COLUMNS = [
            { header: '定位时间', key: '定位时间', class: 'col-locate-time' },
            { header: '纬度', key: '纬度', class: 'col-coords' },
            { header: '经度', key: '经度', class: 'col-coords' },
            { header: '高程', key: '高程', class: 'col-altitude' },
            { header: '自定义数据', key: '自定义数据', class: 'col-custom-data' },
            { header: '浮标标识名字', key: '浮标标识名字', class: 'col-custom-data' } // 新增浮标标识名字列
        ];

        // --- 通用辅助函数 ---
        function escapeHtml(text) {
            var map = {
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#039;'
            };
            return String(text).replace(/[&<>"']/g, function(m) { return map[m]; });
        }

        function highlightText(text, query) {
            if (!query) {
                return escapeHtml(String(text));
            }
            const escapedText = escapeHtml(String(text));
            // 使用 g 确保全局匹配，i 确保不区分大小写
            const regex = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'); 
            return escapedText.replace(regex, match => `<span class="highlight">${match}</span>`);
        }
        
        // --- 消息卡片折叠/展开逻辑 ---
        function bindCardToggleEvents() {
            document.querySelectorAll('.card-header').forEach(header => {
                header.removeEventListener('click', toggleCard); 
                header.addEventListener('click', toggleCard);

                const content = header.nextElementSibling;
                const icon = header.querySelector('.card-toggle-icon');
                if (content && icon) {
                    // Initialize icon state based on content's expanded class
                    if (content.classList.contains('expanded')) {
                        icon.classList.add('rotated');
                    } else {
                        icon.classList.remove('rotated');
                    }
                }
            });
        }

        function toggleCard(event) {
            const header = event.currentTarget;
            const content = header.nextElementSibling;
            const icon = header.querySelector('.card-toggle-icon');
            
            if (content && icon) {
                content.classList.toggle('expanded');
                icon.classList.toggle('rotated');
            }
        }

        // --- ID分组折叠/展开逻辑 ---
        function bindIdGroupToggleEvents() {
            document.querySelectorAll('.id-group-header').forEach(header => {
                header.removeEventListener('click', toggleIdGroup);
                header.addEventListener('click', toggleIdGroup);

                const content = header.nextElementSibling; // .id-group-content
                const icon = header.querySelector('.id-group-toggle-icon');
                if (content && icon) {
                    // Initialize icon state based on content's collapsed class
                    if (content.classList.contains('collapsed')) {
                        icon.classList.add('rotated'); // Collapsed state: arrow rotated
                    } else {
                        icon.classList.remove('rotated'); // Expanded state: arrow default
                    }
                }
            });
        }

        function toggleIdGroup(event) {
            const header = event.currentTarget;
            const content = header.nextElementSibling; // The div.id-group-content
            const icon = header.querySelector('.id-group-toggle-icon');

            if (content && icon) {
                content.classList.toggle('collapsed');
                icon.classList.toggle('rotated');
            }
        }


        // --- 统一的创建消息卡片的函数 (现在在 base.html 中定义) ---
        // totalCount 参数现在仅在 isHistoryView=false (主页概览模式)时有意义
        function createMessageCardHtml(idNumber, msg, highlightQuery, shouldExpand = false, isHistoryView = false, totalCountForId = 0) {
            let cardHtml = '';
            
            const idNumberDisplay = idNumber || 'N/A'; // Ensure IdNumber has value
            
            // Receive time is unique for card header, distinguishes historical messages
            const receiveTimeFormatted = msg['接收时间'];

            // Card Header: Always show Receive Time + Message ID
            // Also display the formatted display_id_name from msg
            let headerText = `
                ${highlightText(msg.display_id_name, highlightQuery)}
                <span class="card-title-text ms-3">接收时间: ${highlightText(receiveTimeFormatted, highlightQuery)}</span>
                <span class="card-title-text ms-3">消息ID: ${highlightText(msg['MessageId'], highlightQuery)}</span>
            `;
            
            let historyLinkHtml = '';
            // Only show "View History" button on main page (not history page) and if idNumber is valid
            // And if totalCountForId > 1, meaning there is actual history
            if (!isHistoryView && idNumberDisplay !== 'N/A' && totalCountForId > 1) { 
                const historyBaseUrl = "{{ url_for('history', id_number_param='') }}";
                const historyFullLink = `${historyBaseUrl}${encodeURIComponent(idNumberDisplay)}`;
                historyLinkHtml = `<a href="${historyFullLink}" class="button secondary small" style="margin-left: 10px;">查看历史(${totalCountForId})</a>`;
            }

            const parseStatusText = msg['解析状态'] ? msg['解析状态'].text : 'N/A';
            const parseStatusClass = msg['解析状态'] ? msg['解析状态'].class : '';
            
            const dataId = msg['数据标识'] || 'N/A';

            const contentClass = `card-content ${shouldExpand ? 'expanded' : ''}`;
            const iconClass = `card-toggle-icon ${shouldExpand ? 'rotated' : ''}`;

            cardHtml += `
                <div class="card id-card-yellow" data-id="${idNumberDisplay}" data-receive-time="${receiveTimeFormatted}">
                    <div class="card-header">
                        <div>${headerText}</div>
                        <div>
                            ${historyLinkHtml}
                            <span class="${iconClass}">▶</span>
                        </div>
                    </div>
                    <div class="${contentClass}">
                        <div class="message-meta">
                            <div class="item">数据标识: <span>${highlightText(dataId, highlightQuery)}</span></div>
                            <div class="item">解析状态: <span class="${parseStatusClass}">${highlightText(parseStatusText, highlightQuery)}</span></div>
                        </div>
                        <table>
                            <thead>
                                <tr>
            `;
            TABLE_COLUMNS.forEach(col => {
                cardHtml += `<th class="${col.class}">${escapeHtml(col.header)}</th>`;
            });

            cardHtml += `
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
            `;
            TABLE_COLUMNS.forEach(col => {
                let displayedValue;
                let valueClass = col.class; 
                let rawValue = msg[col.key];

                if (col.key === '自定义数据' && String(rawValue).length > 50) { 
                    const shortValue = String(rawValue).substring(0, 50) + '...';
                    displayedValue = `
                        <details style="display: block;">
                            <summary>${highlightText(shortValue, highlightQuery)}</summary>
                            <pre class="code-block" style="max-height: 100px;">${highlightText(String(rawValue), highlightQuery)}</pre>
                        </details>
                    `;
                } else {
                    displayedValue = highlightText(String(rawValue || 'N/A'), highlightQuery);
                }
                
                cardHtml += `<td class="${valueClass}">${displayedValue}</td>`;
            });
            
            cardHtml += `
                                </tr>
                            </tbody>
                        </table>
                        
                        {# Raw POST data: displayed on both main and history pages #}
                        ${msg.raw_post_data_json ? `
                        <div style="margin-top: 20px;">
                            <details style="margin-top: 5px;">
                                <summary class="button secondary small" style="cursor: pointer; display: inline-block; padding: 5px 10px; font-size: 0.85em;">点击查看原始POST数据</summary>
                                <pre class="code-block">${highlightText(msg.raw_post_data_json, highlightQuery)}</pre>
                            </details>
                        </div>
                        ` : ''}
                    </div>
                </div>
            `;
            return cardHtml;
        }

        // --- Event Listener for DOMContentLoaded ---
        document.addEventListener('DOMContentLoaded', () => {
            // Flatpickr 初始化逻辑。这里确保它只初始化一次，且 onChange 由各自页面设置。
            // 对于 receiveTimeRangeInput
            const receiveTimeRangeInput = document.getElementById('receiveTimeRange');
            if (receiveTimeRangeInput && !receiveTimeRangeInput._flatpickr) {
                flatpickr(receiveTimeRangeInput, {
                    mode: "range",
                    dateFormat: "Y-m-d H:i:S",
                    enableTime: true,
                    time_24hr: true,
                    locale: "zh",
                    // onChange here is intentionally empty, or a no-op placeholder.
                    // Specific page's script will set its own onChange.
                });
            }

            // 对于 mapTimeRangeInput
            const mapTimeRangeInput = document.getElementById('mapTimeRange');
            if (mapTimeRangeInput && !mapTimeRangeInput._flatpickr) {
                flatpickr(mapTimeRangeInput, {
                    mode: "range",
                    dateFormat: "Y-m-d H:i:S",
                    enableTime: true,
                    time_24hr: true,
                    locale: "zh",
                    // onChange here is intentionally empty, or a no-op placeholder.
                    // Specific page's script will set its own onChange.
                });
            }
        });
    </script>
</body>
</html>
